#include <iostream>
#include <vector>
#include <unistd.h>
#include <cassert>
#include <sys/wait.h>
#include <sys/types.h>
using namespace std;
#include "Task.hpp"
int gnum=3;
Task t;
class EndPoint{
private:
    static int number;
public:
    pid_t _child_id;
    int _write_fd;
    string processname;
public:
    EndPoint(int id,int fd)
        :_child_id(id)
        ,_write_fd(fd)
    {
        char namebuffer[64];
        snprintf(namebuffer,sizeof(namebuffer),"process->%d[%d:%d]",number++,_child_id,_write_fd);
        processname = namebuffer;
    }
    string name() const
    {
        return processname;
    }
    
};
int EndPoint::number=0;
//子进程接收来自父进程的指令
void WaitCommand(){
    while(true){
        int command = 0;
        int n = read(0,&command,sizeof(int));
        if(n==sizeof(int)){
            t.Execute(command);
        }else if(n==0){
            break;
        }else{
            break;
        }
    }
}
void createProcesses(vector<EndPoint>& end_points){
    vector<int> fds;
    for(size_t i=0;i<gnum;++i){
        //1.1 创建管道
        int pipefd[2]={0};
        int n=pipe(pipefd);
        assert(n==0);
        (void)n;

        //1.2创建进程
        pid_t id = fork();
        assert(id!=-1);
        if(id==0){
            for(auto& fd:fds)close(fd);
            //关闭不需要的fd
            close(pipefd[1]);
            //期望所有子进程读取指令的时候，都从标准输入读取
            //输入重定向
            dup2(pipefd[0],0);
            //子进程开始等待获取命令
            WaitCommand();
            close(pipefd[0]);
            exit(0);
        }
        //执行父进程
        //关闭不要的fd
        close(pipefd[0]);

        //将新的子进程和他的管道写端，构建对象
        end_points.push_back(EndPoint(id,pipefd[1]));
        fds.push_back(pipefd[1]);
    }
}
int ShowBoard(){
    cout<<"###########################################"<<endl;
    cout<<" 0.执行日志任务      1.执行数据库任务        "<<endl;
    cout<<" 2.执行请求任务      3.退出                  "<<endl;
    cout<<"###########################################"<<endl;
    cout<<"请选择"<<endl;
    int command=0;
    cin>>command;
    return command;

} 
void ctrlProcess(const vector<EndPoint>& end_points){
    //2.1我们可以写成自动化的，也可以搞成交互式的。
    int num=0;
    int cnt=0;
    while(true)
    {
        //选择任务
        int command = ShowBoard();
        if(command==3)break;
        if(command<0||command>2)continue;

        //选择进程
        int index = cnt++;
        cnt%=end_points.size();
        string name = end_points[index].name();
        cout<<"选择了进程："<<name<<"处理任务："<<command<<endl;

        //下发任务
        write(end_points[index]._write_fd,&command,sizeof(command));
        sleep(1);
    }
}
void waitProcess(const vector<EndPoint>& end_points)
{
    for(int end=0;end<end_points.size();++end){
        cout<<"父进程让子进程退出："<<end_points[end]._child_id<<endl;
        close(end_points[end]._write_fd);

        waitpid(end_points[end]._child_id,nullptr,0);
        cout<<"父进程回收了子进程："<<end_points[end]._child_id<<endl;
    }
}
int main(){
    vector<EndPoint> end_points;//每个子进程的id和管道文件操作符存进end_points
    createProcesses(end_points);
    ctrlProcess(end_points);
    waitProcess(end_points);
    return 0;
}